home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / TTY.java < prev    next >
Text File  |  1998-09-22  |  53KB  |  1,627 lines

  1. /*
  2.  * @(#)TTY.java    1.80 98/07/01
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package sun.tools.ttydebug;
  16. import sun.tools.debug.*;
  17. import java.util.*;
  18. import java.io.*;
  19. import java.net.*;
  20.  
  21. public class TTY implements DebuggerCallback {
  22.     RemoteDebugger debugger;
  23.     RemoteThread currentThread;
  24.     RemoteThreadGroup currentThreadGroup;
  25.     PrintStream out = null;
  26.     PrintStream console = null;
  27.  
  28.     private static final String progname = "jdb";
  29.     private static final String version = "98/07/01";
  30.  
  31.     private String lastArgs = null;
  32.     
  33.     private RemoteThread indexToThread(int index) throws Exception {
  34.     setDefaultThreadGroup();
  35.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  36.     if (index == 0 || index > list.length) {
  37.         return null;
  38.     }
  39.     return list[index-1];
  40.     }
  41.  
  42.     private int parseThreadId(String idToken) throws Exception {
  43.     if (idToken.startsWith("t@")) {
  44.         idToken = idToken.substring(2);
  45.     }
  46.  
  47.     int threadId;
  48.     try {
  49.         threadId = Integer.valueOf(idToken).intValue();
  50.     } catch (NumberFormatException e) {
  51.         threadId = 0;
  52.     }
  53.     if (indexToThread(threadId) == null) {
  54.         out.println("\"" + idToken +
  55.                    "\" is not a valid thread id.");
  56.         return 0;
  57.     }
  58.     return threadId;
  59.     }
  60.  
  61.     private void printPrompt() throws Exception {
  62.         if (currentThread == null) {
  63.             out.print("> ");
  64.         } else {
  65.             out.print(currentThread.getName() + "[" +
  66.                       (currentThread.getCurrentFrameIndex() + 1)
  67.                       + "] ");
  68.         }
  69.         out.flush();
  70.     }
  71.  
  72.     public synchronized void printToConsole(String text) throws Exception {
  73.         console.print(text);
  74.         console.flush();
  75.     }
  76.  
  77.     public void breakpointEvent(RemoteThread t) throws Exception {
  78.     out.print("\nBreakpoint hit: ");
  79.  
  80.     RemoteStackFrame[] stack = t.dumpStack();
  81.     if (stack.length > 0) {
  82.         out.println(stack[0].toString());
  83.             currentThread = t;
  84.     } else {
  85.         out.println("Invalid thread specified in breakpoint.");
  86.     }
  87.         printPrompt();
  88.     }
  89.  
  90.     public void exceptionEvent(RemoteThread t, String errorText) 
  91.       throws Exception {
  92.     out.println("\n" + errorText);
  93.     t.setCurrentFrameIndex(0);
  94.     currentThread = t;
  95.         printPrompt();
  96.     }
  97.  
  98.     public void threadDeathEvent(RemoteThread t) throws Exception {
  99.     out.println("\n" + t.getName() + " died.");
  100.         if (t == currentThread) {
  101.             currentThread = null;
  102.         }
  103.         printPrompt();
  104.     }
  105.  
  106.     public void quitEvent() throws Exception {
  107.         String msg = null;
  108.         if (lastArgs != null) {
  109.             StringTokenizer t = new StringTokenizer(lastArgs);
  110.             if (t.hasMoreTokens()) {
  111.                 msg = new String("\n" + t.nextToken() + " exited");
  112.             }
  113.         }
  114.         if (msg == null) {
  115.             msg = new String("\nThe application exited");
  116.         }
  117.         out.println(msg);
  118.         currentThread = null;
  119.         System.exit(0);
  120.     }
  121.  
  122.     void classes() throws Exception {
  123.     RemoteClass list[] = debugger.listClasses();
  124.  
  125.     out.println("** classes list **");
  126.     for (int i = 0 ; i < list.length ; i++) {
  127.         out.println(list[i].description());
  128.     }
  129.     }
  130.  
  131.     void methods(StringTokenizer t) throws Exception {
  132.     if (!t.hasMoreTokens()) {
  133.         out.println("No class specified.");
  134.         return;
  135.     }
  136.  
  137.     String idClass = t.nextToken();
  138.     try {
  139.         RemoteClass cls = getClassFromToken(idClass);
  140.  
  141.         RemoteField methods[] = cls.getMethods();
  142.         for (int i = 0; i < methods.length; i++) {
  143.         out.println(methods[i].getTypedName());
  144.         }
  145.     } catch (IllegalArgumentException e) {
  146.         out.println("\"" + idClass +
  147.                    "\" is not a valid id or class name.");
  148.     }
  149.     }
  150.  
  151.     int printThreadGroup(RemoteThreadGroup tg, int iThread) throws Exception {
  152.     out.println("Group " + tg.getName() + ":");
  153.     RemoteThread tlist[] = tg.listThreads(false);
  154.  
  155.     int maxId = 0;
  156.     int maxName = 0;
  157.     for (int i = 0 ; i < tlist.length ; i++) {
  158.         int len = tlist[i].description().length();
  159.         if (len > maxId)
  160.         maxId = len;
  161.         String name = tlist[i].getName();
  162.         int iDot = name.lastIndexOf('.');
  163.         if (iDot >= 0 && name.length() > iDot) {
  164.         name = name.substring(iDot + 1);
  165.         }
  166.         if (name.length() > maxName)
  167.         maxName = name.length();
  168.     }
  169.  
  170.         String maxNumString = String.valueOf(iThread + tlist.length);
  171.         int maxNumDigits = maxNumString.length();
  172.  
  173.     for (int i = 0 ; i < tlist.length ; i++) {
  174.         char buf[] = new char[80];
  175.         for (int j = 0; j < 79; j++) {
  176.         buf[j] = ' ';
  177.         }
  178.         buf[79] = '\0';
  179.         StringBuffer sbOut = new StringBuffer();
  180.         sbOut.append(buf);
  181.  
  182.             // Right-justify the thread number at start of output string
  183.             String numString = String.valueOf(iThread + i + 1);
  184.         sbOut.insert(maxNumDigits - numString.length(),
  185.                          numString);
  186.         sbOut.insert(maxNumDigits, ".");
  187.  
  188.         int iBuf = maxNumDigits + 2;
  189.         sbOut.insert(iBuf, tlist[i].description());
  190.         iBuf += maxId + 1;
  191.         String name = tlist[i].getName();
  192.         int iDot = name.lastIndexOf('.');
  193.         if (iDot >= 0 && name.length() > iDot) {
  194.         name = name.substring(iDot + 1);
  195.         }
  196.         sbOut.insert(iBuf, name);
  197.         iBuf += maxName + 1;
  198.         sbOut.insert(iBuf, tlist[i].getStatus());
  199.         sbOut.setLength(79);
  200.         out.println(sbOut.toString());
  201.     }
  202.  
  203.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(tg);
  204.     for (int ig = 0; ig < tglist.length; ig++) {
  205.         if (tg != tglist[ig]) {
  206.         iThread += printThreadGroup(tglist[ig], iThread + tlist.length);
  207.         }
  208.     }
  209.     return tlist.length;
  210.     }
  211.  
  212.     private void setDefaultThreadGroup() throws Exception {
  213.     if (currentThreadGroup == null) {
  214.         RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  215.         currentThreadGroup = tglist[0];    // system threadgroup
  216.     }
  217.     }
  218.     
  219.     void threads(StringTokenizer t) throws Exception {
  220.     if (!t.hasMoreTokens()) {
  221.         setDefaultThreadGroup();
  222.         printThreadGroup(currentThreadGroup, 0);
  223.         return;
  224.     }
  225.     String name = t.nextToken();
  226.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  227.     for (int i = 0; i < tglist.length; i++) {
  228.         if (name.equals(tglist[i].getName())) {
  229.         printThreadGroup(tglist[i], 0);
  230.         return;
  231.         }
  232.     }
  233.     out.println(name + " is not a valid threadgroup name.");
  234.     }
  235.  
  236.     void threadGroups() throws Exception {
  237.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  238.     for (int i = 0; i < tglist.length; i++) {
  239.         out.println(new Integer(i+1).toString() + ". " +
  240.                    tglist[i].description() + " " +
  241.                    tglist[i].getName());
  242.     }
  243.     }
  244.  
  245.     void setThread(int threadId) throws Exception {
  246.     setDefaultThreadGroup();
  247.     RemoteThread thread = indexToThread(threadId);
  248.     if (thread == null) {
  249.         out.println("\"" + threadId +
  250.                    "\" is not a valid thread id.");
  251.         return;
  252.     }
  253.     currentThread = thread;
  254.     }
  255.     
  256.     void thread(StringTokenizer t) throws Exception {
  257.     if (!t.hasMoreTokens()) {
  258.         out.println("Thread number not specified.");
  259.         return;
  260.     }
  261.     int threadId = parseThreadId(t.nextToken());
  262.     if (threadId == 0) {
  263.         return;
  264.     }
  265.     setThread(threadId);
  266.     }
  267.     
  268.     void threadGroup(StringTokenizer t) throws Exception {
  269.     if (!t.hasMoreTokens()) {
  270.         out.println("Threadgroup name not specified.");
  271.         return;
  272.     }
  273.     String name = t.nextToken();
  274.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  275.     for (int i = 0; i < tglist.length; i++) {
  276.         if (name.equals(tglist[i].getName())) {
  277.         currentThreadGroup = tglist[i];
  278.         return;
  279.         }
  280.     }
  281.     out.println(name + " is not a valid threadgroup name.");
  282.     }
  283.     
  284.     void run(StringTokenizer t) throws Exception {
  285.     String argv[] = new String[100];
  286.     int argc = 0;
  287.  
  288.     if (!t.hasMoreTokens() && lastArgs != null) {
  289.         t = new StringTokenizer(lastArgs);
  290.         out.println("run " + lastArgs);
  291.     }
  292.     while (t.hasMoreTokens()) {
  293.         argv[argc++] = t.nextToken();
  294.             if (argc == 1) {
  295.                 // Expand name, if necessary.
  296.                 RemoteClass cls = debugger.findClass(argv[0]);
  297.                 if (cls == null) {
  298.                     out.println("Could not load the " + argv[0] + " class.");
  299.                     return;
  300.                 }
  301.                 argv[0] = cls.getName();
  302.             }
  303.     }
  304.  
  305.     if (argc > 0) {
  306.         RemoteThreadGroup newGroup = debugger.run(argc, argv);
  307.         if (newGroup != null) {
  308.         currentThreadGroup = newGroup;
  309.         setThread(1);
  310.         out.println("running ...");
  311.         } else {
  312.         out.println(argv[0] + " failed.");
  313.         }
  314.     } else {
  315.         out.println("No class name specified.");
  316.     }
  317.     }
  318.  
  319.     void load(StringTokenizer t) throws Exception {
  320.     if (!t.hasMoreTokens()) {
  321.         out.println("Class name not specified.");
  322.         return;
  323.     }
  324.     String idToken = t.nextToken();
  325.     RemoteClass cls = debugger.findClass(idToken);
  326.     if (cls == null) {
  327.         out.print(idToken + " not found");
  328.         out.println((idToken.indexOf('.') > 0) ?
  329.                    " (try the full name)" : "");
  330.     } else {
  331.         out.println(cls.toString());
  332.     }
  333.     }
  334.  
  335.     void suspend(StringTokenizer t) throws Exception {
  336.     if (!t.hasMoreTokens()) {
  337.         setDefaultThreadGroup();
  338.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  339.         for (int i = 0; i < list.length; i++) {
  340.         list[i].suspend();
  341.         }
  342.         out.println("All (non-system) threads suspended.");
  343.     } else {
  344.         while (t.hasMoreTokens()) {
  345.         String idToken = t.nextToken();
  346.         int threadId;
  347.         try {
  348.             threadId = Integer.valueOf(idToken).intValue();
  349.         } catch (NumberFormatException e) {
  350.             threadId = 0;
  351.         }
  352.         RemoteThread thread = indexToThread(threadId);
  353.         if (thread == null) {
  354.             out.println("\"" + idToken +
  355.                        "\" is not a valid thread id.");
  356.             continue;
  357.         }
  358.         thread.suspend();
  359.         }
  360.     }
  361.     }
  362.  
  363.     void resume(StringTokenizer t) throws Exception {
  364.      if (!t.hasMoreTokens()) {
  365.         setDefaultThreadGroup();
  366.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  367.         for (int i = 0; i < list.length; i++) {
  368.         list[i].resume();
  369.         }
  370.         if (currentThread != null) {
  371.         currentThread.resetCurrentFrameIndex();
  372.         }
  373.          out.println("All threads resumed.");
  374.      } else {
  375.          while (t.hasMoreTokens()) {
  376.          String idToken = t.nextToken();
  377.          int threadId;
  378.          try {
  379.              threadId = Integer.valueOf(idToken).intValue();
  380.          } catch (NumberFormatException e) {
  381.              threadId = 0;
  382.          }
  383.         RemoteThread thread = indexToThread(threadId);
  384.         if (thread == null) {
  385.              out.println("\"" + idToken +
  386.                        "\" is not a valid thread id.");
  387.              continue;
  388.          }
  389.          thread.resume();
  390.          if (thread == currentThread) {
  391.              currentThread.resetCurrentFrameIndex();
  392.          }
  393.           }
  394.     }
  395.     }
  396.  
  397.     void cont() throws Exception {
  398.         if (currentThread == null) {
  399.             out.println("Nothing suspended.");
  400.             return;
  401.         }
  402.     debugger.cont();
  403.     }
  404.  
  405.     /* step
  406.      *
  407.      * step up (out of a function).
  408.      * Courtesy of Gordon Hirsch of SAS.
  409.      */
  410.     void step(StringTokenizer t) throws Exception {
  411.     if (currentThread == null) {
  412.         out.println("Nothing suspended.");
  413.         return;
  414.     }
  415.     try {
  416.         if (t.hasMoreTokens()) {
  417.         String nt = t.nextToken().toLowerCase();
  418.         if (nt.equals("up")) {
  419.             currentThread.stepOut();               
  420.         } else {
  421.             currentThread.step(true);
  422.         }
  423.         } else {
  424.         currentThread.step(true);
  425.         }
  426.     } catch (IllegalAccessError e) {
  427.         out.println("Current thread is not suspended.");
  428.     }
  429.     }
  430.  
  431.     /* stepi
  432.      * step instruction.
  433.      * Courtesy of Gordon Hirsch of SAS.
  434.      */
  435.     void stepi() throws Exception {
  436.     if (currentThread == null) {
  437.         out.println("Nothing suspended.");
  438.         return;
  439.     }
  440.     try {
  441.         currentThread.step(false);
  442.     } catch (IllegalAccessError e) {
  443.         out.println("Current thread is not suspended.");
  444.     }
  445.     }
  446.  
  447.     void next() throws Exception {
  448.     if (currentThread == null) {
  449.         out.println("Nothing suspended.");
  450.         return;
  451.     }
  452.     try {
  453.         currentThread.next();
  454.     } catch (IllegalAccessError e) {
  455.         out.println("Current thread is not suspended.");
  456.     }
  457.     }
  458.  
  459.     void kill(StringTokenizer t) throws Exception {
  460.      if (!t.hasMoreTokens()) {
  461.         out.println("Usage: kill <threadgroup name> or <thread id>");
  462.         return;
  463.     }
  464.     while (t.hasMoreTokens()) {
  465.         String idToken = t.nextToken();
  466.         int threadId;
  467.         try {
  468.         threadId = Integer.valueOf(idToken).intValue();
  469.         } catch (NumberFormatException e) {
  470.         threadId = 0;
  471.         }
  472.         RemoteThread thread = indexToThread(threadId);
  473.         if (thread != null) {
  474.                 out.println("killing thread: " + thread.getName());
  475.         thread.stop();
  476.                 return;
  477.         } else {
  478.         /* Check for threadgroup name, skipping "system". */
  479.         RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  480.         tglist = debugger.listThreadGroups(tglist[0]);
  481.         for (int i = 0; i < tglist.length; i++) {
  482.             if (tglist[i].getName().equals(idToken)) {
  483.                         out.println("killing threadgroup: " + idToken);
  484.             tglist[i].stop();
  485.             return;
  486.             }
  487.         }
  488.         
  489.         out.println("\"" + idToken +
  490.                    "\" is not a valid threadgroup or id.");
  491.         }
  492.     }
  493.     }
  494.  
  495.     void catchException(StringTokenizer t) throws Exception {
  496.      if (!t.hasMoreTokens()) {
  497.         String exceptionList[] = debugger.getExceptionCatchList();
  498.         for (int i = 0; i < exceptionList.length; i++) {
  499.         out.print("  " + exceptionList[i]);
  500.         if ((i & 4) == 3 || (i == exceptionList.length - 1)) {
  501.             out.println();
  502.         }
  503.         }
  504.     } else {
  505.         String idClass = t.nextToken();
  506.         try {
  507.         RemoteClass cls = getClassFromToken(idClass);
  508.         cls.catchExceptions();
  509.         } catch (Exception e) {
  510.         out.println("Invalid exception class name: " + idClass);
  511.         }
  512.     }
  513.     }
  514.     
  515.     void ignoreException(StringTokenizer t) throws Exception {
  516.      if (!t.hasMoreTokens()) {
  517.         String exceptionList[] = debugger.getExceptionCatchList();
  518.         for (int i = 0; i < exceptionList.length; i++) {
  519.         out.print("  " + exceptionList[i]);
  520.         if ((i & 4) == 3 || (i == exceptionList.length - 1)) {
  521.             out.println();
  522.         }
  523.         }
  524.     } else {
  525.         String idClass = t.nextToken();
  526.         try {
  527.         RemoteClass cls = getClassFromToken(idClass);
  528.         cls.ignoreExceptions();
  529.         } catch (Exception e) {
  530.         out.println("Invalid exception class name: " + idClass);
  531.         }
  532.     }
  533.     }
  534.     
  535.     void up(StringTokenizer t) throws Exception {
  536.     if (currentThread == null) {
  537.         out.println("Current thread not set.");
  538.         return;
  539.     }
  540.  
  541.     int nLevels = 1;
  542.     if (t.hasMoreTokens()) {
  543.         String idToken = t.nextToken();
  544.         int n;
  545.         try {
  546.         n = Integer.valueOf(idToken).intValue();
  547.         } catch (NumberFormatException e) {
  548.         n = 0;
  549.         }
  550.         if (n == 0) {
  551.         out.println("Usage: up [n frames]");
  552.         return;
  553.         }
  554.         nLevels = n;
  555.     }
  556.  
  557.     try {
  558.         currentThread.up(nLevels);
  559.     } catch (IllegalAccessError e) {
  560.         out.println("Thread isn't suspended.");
  561.     } catch (ArrayIndexOutOfBoundsException e) {
  562.         out.println("End of stack.");
  563.     }
  564.     }
  565.  
  566.     void down(StringTokenizer t) throws Exception {
  567.     if (currentThread == null) {
  568.         out.println("Current thread not set.");
  569.         return;
  570.     }
  571.  
  572.     int nLevels = 1;
  573.     if (t.hasMoreTokens()) {
  574.         String idToken = t.nextToken();
  575.         int n;
  576.         try {
  577.         n = Integer.valueOf(idToken).intValue();
  578.         } catch (NumberFormatException e) {
  579.         n = 0;
  580.         }
  581.         if (n == 0) {
  582.         out.println("usage: down [n frames]");
  583.         return;
  584.         }
  585.         nLevels = n;
  586.     }
  587.  
  588.     try {
  589.         currentThread.down(nLevels);
  590.     } catch (IllegalAccessError e) {
  591.         out.println("Thread isn't suspended.");
  592.     } catch (ArrayIndexOutOfBoundsException e) {
  593.         out.println("End of stack.");
  594.     }
  595.     }
  596.  
  597.     void dumpStack(RemoteThread thread, boolean showPC) throws Exception {
  598.     RemoteStackFrame[] stack = thread.dumpStack();
  599.     if (stack.length == 0) {
  600.         out.println("Thread is not running (no stack).");
  601.     } else {
  602.         int nFrames = stack.length;
  603.         for (int i = thread.getCurrentFrameIndex(); i < nFrames; i++) {
  604.         out.print("  [" + (i + 1) + "] ");
  605.         out.print(stack[i].toString());
  606.         if (showPC) {
  607.             out.print(", pc = " + stack[i].getPC());
  608.         }
  609.         out.println();
  610.         }
  611.     }
  612.     }
  613.  
  614.     void where(StringTokenizer t, boolean showPC) throws Exception {
  615.     if (!t.hasMoreTokens()) {
  616.         if (currentThread == null) {
  617.         out.println("No thread specified.");
  618.         return;
  619.         }
  620.         dumpStack(currentThread, showPC);
  621.     } else {
  622.         String token = t.nextToken();
  623.         if (token.toLowerCase().equals("all")) {
  624.         setDefaultThreadGroup();
  625.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  626.         for (int i = 0; i < list.length; i++) {
  627.             out.println(list[i].getName() + ": ");
  628.             dumpStack(list[i], showPC);
  629.         }
  630.         } else {
  631.         int threadId = parseThreadId(token);
  632.         if (threadId == 0) {
  633.             return;
  634.         }
  635.         dumpStack(indexToThread(threadId), showPC);
  636.         }
  637.     }
  638.     }
  639.  
  640.     void trace(String cmd, StringTokenizer t) throws Exception {
  641.     if (!t.hasMoreTokens()) {
  642.         out.println("(i)trace < \"on\" | \"off\" >");
  643.         return;
  644.     }
  645.     
  646.     String v = t.nextToken();
  647.     boolean traceOn;
  648.     if (v.equals("on")) {
  649.         traceOn = true;
  650.     } else if (v.equals("off")) {
  651.         traceOn = false;
  652.     } else {
  653.         out.println("(i)trace < \"on\" | \"off\" >");
  654.         return;
  655.     }
  656.  
  657.     if (cmd.equals("trace")) {
  658.         debugger.trace(traceOn);
  659.     } else {
  660.         debugger.itrace(traceOn);
  661.     }
  662.     }
  663.  
  664.     void memory() throws Exception {
  665.     out.println("Free: " + debugger.freeMemory() + ", total: " +
  666.                debugger.totalMemory());
  667.     }
  668.  
  669.     void gc() throws Exception {
  670.         RemoteObject[] save_list = new RemoteObject[2];
  671.         save_list[0] = currentThread;
  672.         save_list[1] = currentThreadGroup;
  673.         debugger.gc(save_list);
  674.     }
  675.  
  676.     private RemoteClass getClassFromToken(String idToken) throws Exception {
  677.     RemoteObject obj;
  678.     if (idToken.startsWith("0x") ||
  679.         Character.isDigit(idToken.charAt(0))) {
  680.         /* It's an object id. */
  681.         int id;
  682.         try {
  683.         id = RemoteObject.fromHex(idToken);
  684.         } catch (NumberFormatException e) {
  685.         id = 0;
  686.         }
  687.         if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  688.         throw new IllegalArgumentException();
  689.         } else if (!(obj instanceof RemoteClass)) {
  690.         throw new IllegalArgumentException();
  691.         }
  692.     } else {
  693.         /* It's a class */
  694.         obj = debugger.findClass(idToken);
  695.         if (obj == null) {
  696.         throw new IllegalArgumentException();
  697.         }
  698.     }
  699.     return (RemoteClass)obj;
  700.     }
  701.  
  702.     void listBreakpoints() throws Exception {
  703.         String bkptList[] = debugger.listBreakpoints();
  704.     if (bkptList.length > 0) {
  705.             out.println("Current breakpoints set:");
  706.             for(int i = 0; i < bkptList.length; i++) {
  707.                 out.println("\t" + bkptList[i]);
  708.             }
  709.     } else {
  710.         out.println("No breakpoints set.");
  711.     }
  712.     }
  713.  
  714.     void stop(StringTokenizer t) throws Exception {
  715.     if (!t.hasMoreTokens()) {
  716.         listBreakpoints();
  717.         return;
  718.     }
  719.     
  720.     String idClass = null;
  721.     try {
  722.         String modifier = t.nextToken();
  723.         boolean stopAt;
  724.         if (modifier.equals("at")) {
  725.         stopAt = true;
  726.         } else if (modifier.equals("in")) {
  727.         stopAt = false;
  728.         } else {
  729.         out.println("Usage: stop at <class>:<line_number> or");
  730.         out.println("       stop in <class>.<method_name>");
  731.         return;
  732.         }
  733.  
  734.         if (modifier.equals("at")) {
  735.         idClass = t.nextToken(": \t\n\r");
  736.         RemoteClass cls = getClassFromToken(idClass);
  737.  
  738.         String idLine = t.nextToken();
  739.         int lineno = Integer.valueOf(idLine).intValue();
  740.  
  741.         String err = cls.setBreakpointLine(lineno);
  742.         if (err.length() > 0) {
  743.             out.println(err);
  744.         } else {
  745.             out.println("Breakpoint set at " + cls.getName() +
  746.                        ":" + lineno);
  747.         }
  748.         } else {
  749.         idClass = t.nextToken(": \t\n\r");
  750.                 RemoteClass cls = null;
  751.                 String idMethod = null;
  752.  
  753.                 try {
  754.                     cls = getClassFromToken(idClass);
  755.                 } catch (IllegalArgumentException e) {
  756.                     // Try stripping method from class.method token.
  757.                     int idot = idClass.lastIndexOf(".");
  758.                     if (idot == -1) {
  759.                         out.println("\"" + idClass +
  760.                             "\" is not a valid id or class name.");
  761.                         return;
  762.                     }
  763.                     idMethod = idClass.substring(idot + 1);
  764.                     idClass = idClass.substring(0, idot);
  765.                     cls = getClassFromToken(idClass);
  766.                 }
  767.  
  768.                 if (idMethod == null) {
  769.                     idMethod = t.nextToken();
  770.                 }
  771.                 RemoteField method;
  772.                 try {
  773.                     method = cls.getMethod(idMethod);
  774.  
  775.                     /*
  776.                      * Prevent a breakpoint on overloaded method, since there
  777.                      * is, currently,  no way to choose among the overloads.
  778.                      */
  779.                     RemoteField[] allMethods = cls.getMethods();
  780.                     for (int i = 0; i < allMethods.length; i++) {
  781.                         if (allMethods[i].getName().equals(idMethod)
  782.                                         && (allMethods[i] != method)) {
  783.                             out.println(cls.getName() + "." + idMethod 
  784.                                 + " is overloaded. Use the 'stop at' command to " 
  785.                                 + "set a breakpoint in one of the overloads");
  786.                             return;
  787.                             
  788.                         }
  789.                     }
  790.  
  791.  
  792.                 } catch (NoSuchMethodException nsme) {
  793.             out.println("Class " + cls.getName() +
  794.                        " doesn't have a method " + idMethod);
  795.             return;
  796.         }
  797.         String err = cls.setBreakpointMethod(method);
  798.         if (err.length() > 0) {
  799.             out.println(err);
  800.         } else {
  801.             out.println("Breakpoint set in " + cls.getName() +
  802.                        "." + idMethod);
  803.         }
  804.         }
  805.     } catch (NoSuchElementException e) {
  806.         out.println("Usage: stop at <class>:<line_number> or");
  807.         out.println("       stop in <class>.<method_name>");
  808.     } catch (NumberFormatException e) {
  809.         out.println("Invalid line number.");
  810.     } catch (IllegalArgumentException e) {
  811.         out.println("\"" + idClass +
  812.                    "\" is not a valid id or class name.");
  813.     }
  814.     }
  815.  
  816.     void clear(StringTokenizer t) throws Exception {
  817.     if (!t.hasMoreTokens()) {
  818.         listBreakpoints();
  819.         return;
  820.     }
  821.     
  822.     String idClass = null;
  823.     String idMethod = null;
  824.     RemoteClass cls = null;
  825.     try {
  826.         idClass = t.nextToken(": \t\n\r");
  827.         try {
  828.             cls = getClassFromToken(idClass);
  829.             } catch (IllegalArgumentException e) {
  830.                 // Try stripping method from class.method token.
  831.                 int idot = idClass.lastIndexOf(".");
  832.                 if (idot == -1) {
  833.                     out.println("\"" + idClass +
  834.                         "\" is not a valid id or class name.");
  835.                     return;
  836.                 }
  837.                 idMethod = idClass.substring(idot + 1);
  838.                 idClass = idClass.substring(0, idot);
  839.                 cls = getClassFromToken(idClass);
  840.                 RemoteField method;
  841.                 try {
  842.                     method = cls.getMethod(idMethod);
  843.                 } catch (NoSuchMethodException nsme) {
  844.             out.println("\"" + idMethod + 
  845.                 "\" is not a valid method name of class " +
  846.                 cls.getName());
  847.             return;
  848.         }
  849.         String err = cls.clearBreakpointMethod(method);
  850.             if (err.length() > 0) {
  851.             out.println(err);
  852.             } else {
  853.             out.println("Breakpoint cleared at " + 
  854.                 cls.getName() + "." + idMethod);
  855.         }
  856.         return;
  857.             }
  858.  
  859.         String idLine = t.nextToken();
  860.         int lineno = Integer.valueOf(idLine).intValue();
  861.  
  862.         String err = cls.clearBreakpointLine(lineno);
  863.         if (err.length() > 0) {
  864.         out.println(err);
  865.         } else {
  866.         out.println("Breakpoint cleared at " + cls.getName() +
  867.                    ": " + lineno);
  868.         }
  869.     } catch (NoSuchElementException e) {
  870.         out.println("Usage: clear <class>:<line_number>");
  871.         out.println("   or: clear <class>.<method>");
  872.     } catch (NumberFormatException e) {
  873.         out.println("Usage: clear <class>:<line_number>");
  874.         out.println("   or: clear <class>.<method>");
  875.     } catch (IllegalArgumentException e) {
  876.         out.println("\"" + idClass +
  877.                    "\" is not a valid id or class name.");
  878.     }
  879.     }
  880.  
  881.     void list(StringTokenizer t) throws Exception {
  882.     RemoteStackFrame frame = null;
  883.     if (currentThread == null) {
  884.         out.println("No thread specified.");
  885.         return;
  886.     }
  887.     try {
  888.         frame = currentThread.getCurrentFrame();
  889.     } catch (IllegalAccessError e) {
  890.         out.println("Current thread isn't suspended.");
  891.         return;
  892.     } catch (ArrayIndexOutOfBoundsException e) {
  893.         out.println("Thread is not running (no stack).");
  894.         return;
  895.     }
  896.     
  897.     int lineno;
  898.     if (t.hasMoreTokens()) {
  899.         String id = t.nextToken();
  900.  
  901.             // See if token is a line number.
  902.             try {
  903.                 lineno = Integer.valueOf(id).intValue();
  904.             } catch (NumberFormatException nfe) {
  905.                 // It isn't -- see if it's a method name.
  906.                 try {
  907.                     lineno = frame.getRemoteClass().getMethodLineNumber(id);
  908.                 } catch (NoSuchMethodException iobe) {
  909.                     out.println(id + " is not a valid line number or " +
  910.                                 "method name for class " + 
  911.                                 frame.getRemoteClass().getName());
  912.                     return;
  913.                 } catch (NoSuchLineNumberException nse) {
  914.                     out.println("Line number information not found in " +
  915.                                 frame.getRemoteClass().getName());
  916.                     return;
  917.                 }
  918.             }
  919.     } else {
  920.         lineno = frame.getLineNumber();
  921.     }
  922.     int startLine = (lineno > 4) ? lineno - 4 : 1;
  923.     int endLine = startLine + 9;
  924.  
  925.     InputStream rawSourceFile = frame.getRemoteClass().getSourceFile();
  926.     if (rawSourceFile == null) {
  927.         out.println("Unable to find " + 
  928.                         frame.getRemoteClass().getSourceFileName());
  929.         return;
  930.     }
  931.  
  932.     DataInputStream sourceFile = new DataInputStream(rawSourceFile);
  933.     String sourceLine = null;
  934.  
  935.     /* Skip through file to desired window. */
  936.     for (int i = 1; i <= startLine; i++) {
  937.         sourceLine = sourceFile.readLine();
  938.     }
  939.     if (sourceLine == null) {
  940.         out.println(new Integer(lineno).toString() +
  941.                         " is an invalid line number for the file " +
  942.                         frame.getRemoteClass().getSourceFileName());
  943.     }
  944.  
  945.     /* Print lines */
  946.     for (int i = startLine; i < endLine && sourceLine != null; i++) {
  947.         out.print(new Integer(i).toString() + "\t" +
  948.                  ((i == lineno) ? "=> " : "   "));
  949.         out.println(sourceLine);
  950.         sourceLine = sourceFile.readLine();
  951.     }
  952.         
  953.     }
  954.  
  955.     /* Get or set the source file path list. */
  956.     void use(StringTokenizer t) throws Exception {
  957.     if (!t.hasMoreTokens()) {
  958.         out.println(debugger.getSourcePath());
  959.     } else {
  960.         debugger.setSourcePath(t.nextToken());
  961.     }
  962.     }
  963.  
  964.     /* Print a stack variable */
  965.     private void printVar(RemoteStackVariable var) {
  966.         out.print("  " + var.getName());
  967.         if (var.inScope()) {
  968.             RemoteValue val = var.getValue();
  969.             out.println(" = " + (val == null? "null" : val.toString()) );
  970.         } else {
  971.             out.println(" is not in scope");
  972.         }
  973.     }
  974.  
  975.     /* Print all local variables in current stack frame. */
  976.     void locals() throws Exception {
  977.     if (currentThread == null) {
  978.         out.println("No default thread specified: " +
  979.                    "use the \"thread\" command first.");
  980.         return;
  981.     }
  982.         if (!currentThread.isSuspended()) {
  983.             out.println("Thread isn't suspended.");
  984.             return;
  985.         }
  986.     RemoteStackVariable rsv[] = currentThread.getStackVariables();
  987.     if (rsv == null || rsv.length == 0) {
  988.         out.println("No local variables: try compiling with -g");
  989.         return;
  990.     }
  991.     out.println("Method arguments:");
  992.     for (int i = 0; i < rsv.length; i++) {
  993.         if (rsv[i].methodArgument()) {
  994.         printVar(rsv[i]);
  995.         }
  996.     }
  997.     out.println("Local variables:");
  998.     for (int i = 0; i < rsv.length; i++) {
  999.         if (!rsv[i].methodArgument()) {
  1000.         printVar(rsv[i]);
  1001.             }
  1002.     }
  1003.     return;
  1004.     }
  1005.  
  1006.     static final String printDelimiters = ".[(";
  1007.  
  1008.     /* Print a specified reference. 
  1009.      * New print() implementation courtesy of S. Blackheath of IBM
  1010.      */
  1011.     void print(StringTokenizer t, boolean dumpObject) throws Exception {
  1012.     if (!t.hasMoreTokens()) {
  1013.         out.println("No objects specified.");
  1014.             return;
  1015.     }
  1016.  
  1017.     int id;
  1018.     RemoteValue obj = null;
  1019.  
  1020.         while (t.hasMoreTokens()) {
  1021.         String expr = t.nextToken();
  1022.         StringTokenizer pieces =
  1023.            new StringTokenizer(expr, printDelimiters, true);
  1024.  
  1025.         String idToken = pieces.nextToken(); // There will be at least one.
  1026.         if (idToken.startsWith("t@")) {
  1027.             /* It's a thread */
  1028.             setDefaultThreadGroup();
  1029.             RemoteThread tlist[] = currentThreadGroup.listThreads(true);
  1030.             try {
  1031.                 id = Integer.valueOf(idToken.substring(2)).intValue();
  1032.             } catch (NumberFormatException e) {
  1033.             id = 0;
  1034.             }
  1035.             if (id <= 0 || id > tlist.length) {
  1036.                 out.println("\"" + idToken +
  1037.                    "\" is not a valid thread id.");
  1038.                     continue;
  1039.             }
  1040.             obj = tlist[id - 1];
  1041.  
  1042.         } else if (idToken.startsWith("$s")) {
  1043.             int slotnum;
  1044.             try {
  1045.                 slotnum = Integer.valueOf(idToken.substring(2)).intValue();
  1046.             } catch (NumberFormatException e) {
  1047.  
  1048.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1049.                     continue;
  1050.             }
  1051.             if (currentThread != null) {
  1052.                 RemoteStackVariable rsv[] = currentThread.getStackVariables();
  1053.             if (rsv == null || slotnum >= rsv.length) {
  1054.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1055.                         continue;
  1056.             }
  1057.             obj = rsv[slotnum].getValue();
  1058.             }
  1059.         
  1060.         } else if (idToken.startsWith("0x") ||
  1061.                Character.isDigit(idToken.charAt(0))) {
  1062.             /* It's an object id. */
  1063.             try {
  1064.                 id = RemoteObject.fromHex(idToken);
  1065.             } catch (NumberFormatException e) {
  1066.                 id = 0;
  1067.             }
  1068.                 if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  1069.                 out.println("\"" + idToken + "\" is not a valid id.");
  1070.                     continue;
  1071.             }
  1072.         } else {
  1073.             /* See if it's a local stack variable */
  1074.                 RemoteStackVariable rsv = null;
  1075.             if (currentThread != null) {
  1076.             rsv = currentThread.getStackVariable(idToken);
  1077.             if (rsv != null && !rsv.inScope()) {
  1078.                 out.println(idToken + " is not in scope.");
  1079.                         continue;
  1080.             }
  1081.             obj = (rsv == null) ? null : rsv.getValue();
  1082.             }
  1083.             if (rsv == null) {
  1084.                     String error = null;
  1085.                     /* See if it's an instance variable */
  1086.                     String instanceStr = idToken;
  1087.                     try {
  1088.                         instanceStr = instanceStr + pieces.nextToken("");
  1089.                     }
  1090.                     catch (NoSuchElementException e) {}
  1091.  
  1092.                     if (currentThread != null)
  1093.                         rsv = currentThread.getStackVariable("this");
  1094.                     if (rsv != null && rsv.inScope()) {
  1095.                         obj = rsv.getValue();
  1096.  
  1097.                         error = printModifiers(expr,
  1098.                               new StringTokenizer("."+instanceStr, printDelimiters, true),
  1099.                               dumpObject, obj, true);
  1100.                         if (error == null)
  1101.                             continue;
  1102.                     }
  1103.  
  1104.                     // If the above failed, then re-construct the same
  1105.                     // string tokenizer we had before.
  1106.                     pieces = new StringTokenizer(instanceStr, printDelimiters, true);
  1107.                     idToken = pieces.nextToken();
  1108.  
  1109.             /* Try interpreting it as a class */
  1110.                     while (true) {
  1111.                 obj = debugger.findClass(idToken);
  1112.                 if (obj != null)             // break if this is a valid class name
  1113.                             break;
  1114.                         if (!pieces.hasMoreTokens()) // break if we run out of input
  1115.                             break;
  1116.                         String dot = pieces.nextToken();
  1117.                         if (!dot.equals("."))        // break if this token is not a dot
  1118.                             break;
  1119.                         if (!pieces.hasMoreTokens())
  1120.                             break;
  1121.                         // If it is a dot, then add the next token, and loop
  1122.                         idToken = idToken + dot + pieces.nextToken();
  1123.                     }
  1124.                     if (obj == null) {
  1125.                         if (error == null)
  1126.                     error = "\"" + expr + "\" is not a " + "valid local or class name.";
  1127.                     }
  1128.                     else {
  1129.                         String error2 = printModifiers(expr, pieces, dumpObject, obj, false);
  1130.                         if (error2 == null)
  1131.                             continue;
  1132.                         if (error == null)
  1133.                             error = error2;
  1134.                     }
  1135.                     out.println(error);
  1136.                     continue;
  1137.             }
  1138.         }
  1139.             String error = printModifiers(expr, pieces, dumpObject, obj, false);
  1140.             if (error != null)
  1141.                 out.println(error);
  1142.         }
  1143.     }
  1144.  
  1145.     String printModifiers(String expr, StringTokenizer pieces, boolean dumpObject, RemoteValue obj,
  1146.         boolean could_be_local_or_class)
  1147.         throws Exception
  1148.     {
  1149.         RemoteInt noValue = new RemoteInt(-1);
  1150.         RemoteValue rv = noValue;
  1151.  
  1152.         // If the object is null, or a non-object type (integer, array, etc...)
  1153.         // then the value must be in rv.
  1154.         if (obj == null)
  1155.             rv = null;
  1156.         else
  1157.         if (!obj.isObject())
  1158.             rv = obj;
  1159.  
  1160.     String lastField = "";
  1161.     String idToken = pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1162.     while (idToken != null) {
  1163.  
  1164.         if (idToken.equals(".")) {
  1165.             if (pieces.hasMoreTokens() == false) {
  1166.             return "\"" + expr + "\" is not a valid expression.";
  1167.         }
  1168.         idToken = pieces.nextToken();
  1169.  
  1170.         if (rv != noValue) {
  1171.             /* attempt made to get a field on a non-object */
  1172.             return "\"" + lastField + "\" is not an object.";
  1173.         }
  1174.         lastField = idToken;
  1175.  
  1176.                 /* Rather than calling RemoteObject.getFieldValue(), we do this so that
  1177.                  * we can report an error if the field doesn't exist. */
  1178.                 {
  1179.                 RemoteField fields[] = ((RemoteObject)obj).getFields();
  1180.                     boolean found = false;
  1181.                     for (int i = fields.length-1; i >= 0; i--)
  1182.                         if (idToken.equals(fields[i].getName())) {
  1183.                             rv = ((RemoteObject)obj).getFieldValue(i);
  1184.                             found = true;
  1185.                             break;
  1186.                         }
  1187.  
  1188.                     if (!found) {
  1189.                         if (could_be_local_or_class)
  1190.                             /* expr is used here instead of idToken, because:
  1191.                              *   1. we know that we're processing the first token in the line,
  1192.                              *   2. if the user specified a class name with dots in it, 'idToken'
  1193.                              *      will only give the first token. */
  1194.                             return "\"" + expr + "\" is not a valid local, class name, or field of "
  1195.                                 + obj.description();
  1196.                         else
  1197.                             return "\"" + idToken + "\" is not a valid field of "
  1198.                                 + obj.description();
  1199.                     }
  1200.                 }
  1201.  
  1202.                   // don't give long error message next time round the loop
  1203.                 could_be_local_or_class = false;
  1204.  
  1205.         if (rv != null && rv.isObject()) {
  1206.             obj = rv;
  1207.             rv = noValue;
  1208.         }
  1209.         idToken =
  1210.             pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1211.  
  1212.         } else if (idToken.equals("[")) {
  1213.         if (pieces.hasMoreTokens() == false) {
  1214.             return "\"" + expr +
  1215.                     "\" is not a valid expression.";
  1216.         }
  1217.         idToken = pieces.nextToken("]");
  1218.         try {
  1219.             int index = Integer.valueOf(idToken).intValue();
  1220.             rv = ((RemoteArray)obj).getElement(index);
  1221.         } catch (NumberFormatException e) {
  1222.             return "\"" + idToken +
  1223.                        "\" is not a valid decimal number.";
  1224.         } catch (ArrayIndexOutOfBoundsException e) {
  1225.             return idToken + " is out of bounds for " +
  1226.                 obj.description();
  1227.         }
  1228.         if (rv != null && rv.isObject()) {
  1229.             obj = rv;
  1230.             rv = noValue;
  1231.         }
  1232.         if (pieces.hasMoreTokens() == false ||
  1233.             (idToken = pieces.nextToken()).equals("]") == false) {
  1234.             return "\"" + expr +
  1235.                         "\" is not a valid expression.";
  1236.         }
  1237.         idToken = pieces.hasMoreTokens() ?
  1238.             pieces.nextToken(printDelimiters) : null;
  1239.  
  1240.         } else if (idToken.equals("(")) {
  1241.             return "print <method> not supported yet.";
  1242.         } else {
  1243.         /* Should never get here. */
  1244.         return "invalid expression";
  1245.         }
  1246.     }
  1247.  
  1248.     out.print(expr + " = ");
  1249.     if (rv != noValue) {
  1250.         out.println((rv == null) ? "null" : rv.description());
  1251.     } else if (dumpObject && obj instanceof RemoteObject) {
  1252.         out.println(obj.description() + " {");
  1253.  
  1254.         if (obj instanceof RemoteClass) {
  1255.         RemoteClass cls = (RemoteClass)obj;
  1256.  
  1257.         out.print("    superclass = ");
  1258.         RemoteClass superClass = cls.getSuperclass();
  1259.         out.println((superClass == null) ?
  1260.                    "null" : superClass.description());
  1261.  
  1262.         out.print("    loader = ");
  1263.         RemoteObject loader = cls.getClassLoader();
  1264.         out.println((loader == null) ?
  1265.                    "null" : loader.description());
  1266.  
  1267.         RemoteClass interfaces[] = cls.getInterfaces();
  1268.         if (interfaces != null && interfaces.length > 0) {
  1269.             out.println("    interfaces:");
  1270.             for (int i = 0; i < interfaces.length; i++) {
  1271.                 out.println("        " + interfaces[i]);
  1272.             }
  1273.         }
  1274.         }
  1275.  
  1276.         RemoteField fields[] = ((RemoteObject)obj).getFields();
  1277.         if (obj instanceof RemoteClass && fields.length > 0) {
  1278.         out.println();
  1279.         }
  1280.         for (int i = 0; i < fields.length; i++) {
  1281.         String name = fields[i].getTypedName();
  1282.         String modifiers = fields[i].getModifiers();
  1283.         out.print("    " + modifiers + name + " = ");
  1284.         RemoteValue v = ((RemoteObject)obj).getFieldValue(i);
  1285.         out.println((v == null) ? "null" : v.description());
  1286.         }
  1287.         out.println("}");
  1288.     } else {
  1289.             out.println(obj.toString());
  1290.         }
  1291.         return null;
  1292.     }
  1293.  
  1294.     void help() {
  1295.         out.println("** command list **");
  1296.         out.println("threads [threadgroup]     -- list threads");
  1297.         out.println("thread <thread id>        -- set default thread");
  1298.         out.println("suspend [thread id(s)]    -- suspend threads (default: all)");
  1299.         out.println("resume [thread id(s)]     -- resume threads (default: all)");
  1300.         out.println("where [thread id] | all   -- dump a thread's stack");
  1301.         out.println("wherei [thread id] | all  -- dump a thread's stack, with pc info");
  1302.         out.println("threadgroups              -- list threadgroups");
  1303.         out.println("threadgroup <name>        -- set current threadgroup\n");
  1304.         out.println("print <id> [id(s)]        -- print object or field");
  1305.         out.println("dump <id> [id(s)]         -- print all object information\n");
  1306.         out.println("locals                    -- print all local variables in current stack frame\n");
  1307.         out.println("classes                   -- list currently known classes");
  1308.         out.println("methods <class id>        -- list a class's methods\n");
  1309.         out.println("stop in <class id>.<method> -- set a breakpoint in a method");
  1310.         out.println("stop at <class id>:<line> -- set a breakpoint at a line");
  1311.         out.println("up [n frames]             -- move up a thread's stack");
  1312.         out.println("down [n frames]           -- move down a thread's stack");
  1313.         out.println("clear <class id>:<line>   -- clear a breakpoint");
  1314.         out.println("step                      -- execute current line");
  1315.         out.println("step up                   -- execute until the current method returns to its caller");  // SAS GVH step out
  1316.         out.println("stepi                     -- execute current instruction");
  1317.         out.println("next                      -- step one line (step OVER calls)");
  1318.         out.println("cont                      -- continue execution from breakpoint\n");
  1319.         out.println("catch <class id>          -- break for the specified exception");
  1320.         out.println("ignore <class id>         -- ignore when the specified exception\n");
  1321.         out.println("list [line number|method] -- print source code");
  1322.         out.println("use [source file path]    -- display or change the source path\n");
  1323.         out.println("memory                    -- report memory usage");
  1324.         out.println("gc                        -- free unused objects\n");
  1325.         out.println("load classname            -- load Java class to be debugged");
  1326.         out.println("run <class> [args]        -- start execution of a loaded Java class");
  1327. //        out.println("kill <thread(group)>      -- kill a thread or threadgroup\n");
  1328.         out.println("!!                        -- repeat last command");
  1329.         out.println("help (or ?)               -- list commands");
  1330.         out.println("exit (or quit)            -- exit debugger");
  1331.     }
  1332.  
  1333.     void executeCommand(StringTokenizer t) {
  1334.     String cmd = t.nextToken().toLowerCase();
  1335.  
  1336.     try {
  1337.         if (cmd.equals("print")) {
  1338.         print(t, false);
  1339.         } else if (cmd.equals("dump")) {
  1340.         print(t, true);
  1341.         } else if (cmd.equals("locals")) {
  1342.         locals();
  1343.         } else if (cmd.equals("classes")) {
  1344.         classes();
  1345.         } else if (cmd.equals("methods")) {
  1346.         methods(t);
  1347.         } else if (cmd.equals("threads")) {
  1348.         threads(t);
  1349.         } else if (cmd.equals("thread")) {
  1350.         thread(t);
  1351.         } else if (cmd.equals("suspend")) {
  1352.         suspend(t);
  1353.         } else if (cmd.equals("resume")) {
  1354.         resume(t);
  1355.         } else if (cmd.equals("threadgroups")) {
  1356.         threadGroups();
  1357.         } else if (cmd.equals("threadgroup")) {
  1358.         threadGroup(t);
  1359.         } else if (cmd.equals("catch")) {
  1360.         catchException(t);
  1361.         } else if (cmd.equals("ignore")) {
  1362.         ignoreException(t);
  1363.         } else if (cmd.equals("cont")) {
  1364.         cont();
  1365.         } else if (cmd.equals("step")) {
  1366.         step(t);
  1367.         } else if (cmd.equals("stepi")) {
  1368.         stepi();
  1369.         } else if (cmd.equals("next")) {
  1370.         next();
  1371.             } else if (cmd.equals("kill")) {
  1372.                 kill(t);
  1373.         } else if (cmd.equals("where")) {
  1374.         where(t, false);
  1375.         } else if (cmd.equals("wherei")) {
  1376.         where(t, true);
  1377.         } else if (cmd.equals("up")) {
  1378.         up(t);
  1379.         } else if (cmd.equals("down")) {
  1380.         down(t);
  1381.         } else if (cmd.equals("load")) {
  1382.         load(t);
  1383.         } else if (cmd.equals("run")) {
  1384.         run(t);
  1385.         } else if (cmd.equals("memory")) {
  1386.         memory();
  1387.             } else if (cmd.equals("gc")) {
  1388.                 gc();
  1389. //                   This cannot reasonably work
  1390. //        } else if (cmd.equals("trace") || cmd.equals("itrace")) {
  1391. //        trace(cmd, t);
  1392.         } else if (cmd.equals("stop")) {
  1393.         stop(t);
  1394.         } else if (cmd.equals("clear")) {
  1395.         clear(t);
  1396.         } else if (cmd.equals("list")) {
  1397.         list(t);
  1398.         } else if (cmd.equals("use")) {
  1399.         use(t);
  1400.         } else if (cmd.equals("help") || cmd.equals("?")) {
  1401.         help();
  1402.         } else if (cmd.equals("quit") || cmd.equals("exit")) {
  1403.         debugger.close();
  1404.         System.exit(0);
  1405.         } else {
  1406.         out.println("huh? Try help...");
  1407.         }
  1408.     } catch (Exception e) {
  1409.         out.println("Internal exception:");
  1410.         out.flush();
  1411.         e.printStackTrace();
  1412.     }
  1413.     }
  1414.  
  1415.     void readCommandFile(File f) {
  1416.     try {
  1417.         if (f.canRead()) {
  1418.         // Process initial commands.
  1419.         DataInputStream inFile = 
  1420.             new DataInputStream(new FileInputStream(f));
  1421.         String ln;
  1422.         while ((ln = inFile.readLine()) != null) {
  1423.             StringTokenizer t = new StringTokenizer(ln);
  1424.             if (t.hasMoreTokens()) {
  1425.             executeCommand(t);
  1426.             }
  1427.         }
  1428.         }
  1429.     } catch (IOException e) {}
  1430.     }
  1431.  
  1432.     public TTY(String host, String password, String javaArgs, String args, 
  1433.                PrintStream outStream, PrintStream consoleStream,
  1434.                boolean verbose) throws Exception {
  1435.         System.out.println("Initializing " + progname + "...");
  1436.     out = outStream;
  1437.     console = consoleStream;
  1438.         if (password == null) {
  1439.             debugger = new RemoteDebugger(javaArgs, this, verbose);
  1440.         } else {
  1441.             debugger = new RemoteDebugger(host, password, this, verbose);
  1442.         }
  1443.     DataInputStream in = new DataInputStream(System.in);
  1444.     String lastLine = null;
  1445.  
  1446.     if (args != null && args.length() > 0) {
  1447.         StringTokenizer t = new StringTokenizer(args);
  1448.         load(t);
  1449.         lastArgs = args;
  1450.     }
  1451.  
  1452.     Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
  1453.  
  1454.     // Try reading user's startup file.
  1455.     File f = new File(System.getProperty("user.home") + 
  1456.         System.getProperty("file.separator") + "jdb.ini");
  1457.         if (!f.canRead()) {
  1458.             // Try opening $HOME/jdb.ini
  1459.             f = new File(System.getProperty("user.home") + 
  1460.                          System.getProperty("file.separator") + ".jdbrc");
  1461.         }
  1462.         readCommandFile(f);
  1463.  
  1464.     // Try opening local jdb.ini
  1465.     f = new File(System.getProperty("user.dir") + 
  1466.         System.getProperty("file.separator") + "startup.jdb");
  1467.         readCommandFile(f);
  1468.  
  1469.     // Process interactive commands.
  1470.     while (true) {
  1471.             printPrompt();
  1472.         String ln = in.readLine();
  1473.         if (ln == null) {
  1474.         out.println("Input stream closed.");
  1475.         return;
  1476.         }
  1477.  
  1478.         if (ln.startsWith("!!") && lastLine != null) {
  1479.         ln = lastLine + ln.substring(2);
  1480.         out.println(ln);
  1481.         }
  1482.  
  1483.         StringTokenizer t = new StringTokenizer(ln);
  1484.         if (t.hasMoreTokens()) {
  1485.         lastLine = ln;
  1486.         executeCommand(t);
  1487.         }
  1488.     }
  1489.     }
  1490.  
  1491.     private static void usage() {
  1492.         System.out.println("Usage: " + progname + " <options> <classes>");
  1493.         System.out.println();
  1494.         System.out.println("where options include:");
  1495.         System.out.println("    -help             print out this message and exit");
  1496.         System.out.println("    -version          print out the build version and exit");
  1497.         System.out.println("    -host <hostname>  host machine of interpreter to attach to");
  1498.         System.out.println("    -password <psswd> password of interpreter to attach to (from -debug)");
  1499.         System.out.println("options forwarded to debuggee process:");
  1500.         System.out.println("    -v -verbose       turn on verbose mode");
  1501.         System.out.println("    -debug            enable remote JAVA debugging");
  1502.         System.out.println("    -noasyncgc        don't allow asynchronous garbage collection");
  1503.         System.out.println("    -verbosegc        print a message when garbage collection occurs");
  1504.         System.out.println("    -noclassgc        disable class garbage collection");
  1505.         System.out.println("    -cs -checksource  check if source is newer when loading classes");
  1506.         System.out.println("    -ss<number>       set the maximum native stack size for any thread");
  1507.         System.out.println("    -oss<number>      set the maximum Java stack size for any thread");
  1508.         System.out.println("    -ms<number>       set the initial Java heap size");
  1509.         System.out.println("    -mx<number>       set the maximum Java heap size");
  1510.         System.out.println("    -D<name>=<value>  set a system property");
  1511.         System.out.println("    -classpath <directories separated by colons>");
  1512.         System.out.println("                      list directories in which to look for classes");
  1513.         System.out.println("    -prof[:<file>]    output profiling data to ./java.prof or ./<file>");
  1514.         System.out.println("    -verify           verify all classes when read in");
  1515.         System.out.println("    -verifyremote     verify classes read in over the network [default]");
  1516.         System.out.println("    -noverify         do not verify any class");
  1517.         System.out.println("    -dbgtrace         print info for debugging " + progname);
  1518.         System.out.println();
  1519.         System.out.println("For command help type 'help' at " + progname + " prompt");
  1520.     }
  1521.  
  1522.     public static void main(String argv[]) {
  1523.     // Get host attribute, if any.
  1524.     String localhost;
  1525.     try {
  1526.         localhost = InetAddress.getLocalHost().getHostName();
  1527.     } catch (Exception ex) {
  1528.         localhost = null;
  1529.     }    
  1530.     if (localhost == null) {
  1531.         localhost = "localhost";
  1532.     }
  1533.     String host = null;
  1534.     String password = null;
  1535.     String cmdLine = "";
  1536.     String javaArgs = "";
  1537.         boolean verbose = false;
  1538.     
  1539.     for (int i = 0; i < argv.length; i++) {
  1540.         String token = argv[i];
  1541.         if (token.equals("-dbgtrace")) {
  1542.         verbose = true;
  1543.         } else if (token.equals("-cs") || token.equals("-checksource") ||
  1544.                token.equals("-noasyncgc") || token.equals("-prof") ||
  1545.                token.equals("-v") || token.equals("-verbose") ||
  1546.                token.equals("-verify") || token.equals("-noverify") ||
  1547.                token.equals("-verifyremote") ||
  1548.                token.equals("-verbosegc") ||
  1549.                token.startsWith("-ms") || token.startsWith("-mx") ||
  1550.                token.startsWith("-ss") || token.startsWith("-oss") ||
  1551.                token.startsWith("-D")) {
  1552.         javaArgs += token + " ";
  1553.         } else if (token.equals("-classpath")) {
  1554.         if (i == (argv.length - 1)) {
  1555.             System.out.println("No classpath specified.");
  1556.             usage();
  1557.             System.exit(1);
  1558.         }
  1559.         javaArgs += token + " " + argv[++i] + " ";
  1560.         } else if (token.equals("-host")) {
  1561.         if (i == (argv.length - 1)) {
  1562.             System.out.println("No host specified.");
  1563.             usage();
  1564.             System.exit(1);
  1565.         }
  1566.         host = argv[++i];
  1567.         } else if (token.equals("-password")) {
  1568.         if (i == (argv.length - 1)) {
  1569.             System.out.println("No password specified.");
  1570.             usage();
  1571.             System.exit(1);
  1572.         }
  1573.         password = argv[++i];
  1574.         } else if (token.equals("-help")) {
  1575.         usage();
  1576.         System.exit(0);
  1577.         } else if (token.equals("-version")) {
  1578.         System.out.println(progname + " version " + version);
  1579.         System.exit(0);
  1580.         } else if (token.startsWith("-")) {
  1581.         System.out.println("invalid option: " + token);
  1582.         usage();
  1583.         System.exit(1);
  1584.         } else {
  1585.                 // Everything from here is part of the command line
  1586.                 cmdLine = token + " ";
  1587.                 for (i++; i < argv.length; i++) {
  1588.                     cmdLine += argv[i] + " ";
  1589.                 }
  1590.                 break;
  1591.         }
  1592.     }
  1593.     if (host != null && password == null) {
  1594.         System.out.println("A debug password must be specified for " +
  1595.                    "remote debugging.");
  1596.         System.exit(1);
  1597.     }
  1598.     if (host == null) {
  1599.         host = localhost;
  1600.     }
  1601.  
  1602.     try {
  1603.         if (!host.equals(localhost) && password.length() == 0) {
  1604.         System.out.println(
  1605.             "No password supplied for accessing remote " +
  1606.             "Java interpreter.");
  1607.         System.out.println(
  1608.             "The password is reported by the remote interpreter" +
  1609.             "when it is started.");
  1610.                 System.exit(1);
  1611.             }
  1612.             new TTY(host, password, javaArgs, cmdLine, 
  1613.                     System.out, System.out, verbose);
  1614.     } catch(SocketException se) {
  1615.         System.out.println("Failed accessing debugging session on " +
  1616.                    host + ": invalid password.");
  1617.     } catch(NumberFormatException ne) {
  1618.         System.out.println("Failed accessing debugging session on " +
  1619.                    host + ": invalid password.");
  1620.     } catch(Exception e) {        
  1621.         System.out.print("Internal exception:  ");
  1622.         System.out.flush();
  1623.         e.printStackTrace();
  1624.     }
  1625.     }
  1626. }
  1627.